#include "StdAfx.h"
#include <MyFC/Utility.h>
#include <MyControls/Panels.h>
#include <MyControls/Frame.h>
#include <MyControls/Constants.h>
#include <xtd/functional.h>

namespace My {

// Panel

Panel::Panel(Frame & f) 
	: m_Frame(f)
{
	m_pOwner = 0;
	m_Alignment = Panel::ALIGN_CLIENT;
}

int Panel::GetHeaderHeight() const
{
	const CFont * pFont = Widget::Font();
	CDC * pDC = CDC::FromHandle(::GetDC(0));
	int cy;
	{
		SaveObjects save(pDC);
		pDC->SelectObject(const_cast<CFont *>(pFont));
		cy = pDC->GetTextExtent("A").cy + 2;
	}
	ReleaseDC(0, pDC->m_hDC);
	return cy;
}

CSize Panel::GetMinWindowSize() const
{
	CSize s = GetMinClientSize();
	s.cy += GetHeaderHeight();
	return s;
}

void Panel::SetCaption(const String & s)
{
	if (s != m_Caption)
	{
		m_Caption = s;
		Invalidate();
	}
}

void Panel::SetAlignment(int a)
{
	if (a != m_Alignment)
	{
		m_Alignment = a;
		if (m_pOwner != 0)
			m_pOwner->LayoutControls();
	}
}

void Panel::HandlePaint(CDC * pDC, const CRect & r)
{
	CRect rClient = ClientRect();
	CBrush face(GetSysColor(COLOR_BTNFACE));
	pDC->FillRect(&r, &face);
	CRect rHeader(rClient);
	rHeader.bottom = rHeader.top + GetHeaderHeight();

	COLORREF cS = ::GetSysColor(COLOR_BTNSHADOW);
	COLORREF cBlack = RGB(0, 0, 0);
	COLORREF cHeader = ::My::MeanColor(cS, My::MeanColor(cS, cBlack));

	CBrush header(cHeader);
	pDC->FillRect(&rHeader, &header);
	rHeader.InflateRect(-2, 0);
	pDC->SetTextColor(RGB(255, 255, 255));
	pDC->SetBkMode(TRANSPARENT);
	pDC->DrawText(m_Caption.c_str(), &rHeader, DT_SINGLELINE|DT_END_ELLIPSIS|DT_LEFT|DT_VCENTER);
}

// PanelBar

PanelBar::PanelBar(Frame & f) 
	: m_Frame(f) 
{
}

PanelBar::~PanelBar()
{
	xtd::for_each(m_AutoPanels, xtd::deleter());
}

CSize PanelBar::GetMinWindowSize() const
{
	CSize r(0, 0);
	int horz = 0, vert = 0;
	PanelList::const_iterator it;
	for (it = m_Panels.begin(); it != m_Panels.end(); ++it) 
	{
		Panel * pPanel = * it;
		if (!pPanel->Visible())
			continue;
		CSize s = pPanel->GetMinWindowSize();
		switch(pPanel->GetAlignment()) {
			case Panel::ALIGN_CLIENT:
				if (horz + s.cx > r.cx)
					r.cx = horz + s.cx;
				if (vert + s.cy > r.cy)
					r.cy = vert + s.cy;
				break;
			case Panel::ALIGN_LEFT:
			case Panel::ALIGN_RIGHT:
				r.cx += s.cx;
				horz += s.cx;
				if (r.cy < s.cy)
					r.cy = s.cy;
				break;
			case Panel::ALIGN_TOP:
			case Panel::ALIGN_BOTTOM:
				vert += s.cy;
				r.cy += s.cy;
				if (r.cx < s.cx)
					r.cx = s.cx;
				break;
			default:
				continue;
		}
	}
	return r;
}

void PanelBar::HandleVisible(bool on)
{
	m_Frame.RecalcLayout();
}

void PanelBar::LayoutControls()
{
	CRect r = ClientRect();
	for (PanelIndex it = m_Panels.begin(); it != m_Panels.end(); ++it) 
	{
		Panel * pPanel = * it;
		if (!pPanel->Visible())
			continue;
		if (r.IsRectEmpty()) {
			pPanel->SetBounds(r);
			continue;
		}
		CRect b = r;
		CSize s = pPanel->GetMinWindowSize();
		switch(pPanel->GetAlignment()) {
			case Panel::ALIGN_CLIENT:
				r.SetRectEmpty();
				break;
			case Panel::ALIGN_LEFT:
				if (s.cx < b.Width())
					b.right = b.left + s.cx;
				r.left += b.Width();
				break;
			case Panel::ALIGN_RIGHT:
				if (s.cx < b.Width())
					b.left = b.right - s.cx;
				r.right -= b.Width();
				break;
			case Panel::ALIGN_TOP:
				if (s.cy < b.Height())
					b.bottom = b.top + s.cy;
				r.top += b.Height();
				break;
			case Panel::ALIGN_BOTTOM:
				if (s.cy < b.Height())
					b.top = b.bottom - s.cy;
				r.bottom -= b.Height();
				break;
			default:
				continue;
		}
		pPanel->SetBounds(b);
	}
}

void PanelBar::AddPanel(Panel * pPanel)
{
	if (pPanel->m_pOwner == this)
		return;
	
	Container::Add(pPanel);

	assert(pPanel->m_pOwner == 0);
	pPanel->m_pOwner = this;
	pPanel->m_Index = m_Panels.insert(m_Panels.end(), pPanel);

	LayoutControls();
}

void PanelBar::RemovePanel(Panel * pPanel)
{
	Container::Remove(pPanel);

	assert(pPanel->m_pOwner == this);
	m_Panels.erase(pPanel->m_Index);
	pPanel->m_pOwner = 0;
	pPanel->m_Index = 0;

	LayoutControls();
}

WidgetPanel * PanelBar::AddWidget(Widget & widget, const String & caption, int alignment, int border)
{
	WidgetPanel * pPanel = new WidgetPanel(m_Frame, widget, border);
	pPanel->SetCaption(caption);
	pPanel->SetAlignment(alignment);
	m_AutoPanels.push_back(pPanel);
	AddPanel(pPanel);
	return pPanel;
}

void PanelBar::HandlePaint(CDC * pDC, const CRect & r)
{
	CRect rClient = ClientRect();
	CBrush face; face.CreateSysColorBrush(COLOR_BTNFACE);
	pDC->FillRect(&r, &face);
}

// ToolPanelBar

ToolPanelBar::ToolPanelBar(Frame & f) : PanelBar(f) 
{
	m_Frame.Add(this);
}

CRect ToolPanelBar::Bounds() const
{
	CRect r = m_Frame.GetClientRect();
	if (m_Frame.IsStatusBarVisible())
		r.bottom -= StatusHeight;
	CSize s = GetMinWindowSize();
	r.right = r.left + s.cx;
	if (m_Frame.m_BottomBar.Visible())
		r.bottom -= m_Frame.m_BottomSplit;
	r.bottom -= SplitterSize;
	return r;
}

void ToolPanelBar::HandlePaint(CDC * pDC, const CRect & r)
{
	PanelBar::HandlePaint(pDC, r);
	CRect rClient = ClientRect();
	SaveObjects save(pDC);
	CPen pShadow(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
	pDC->SelectObject(&pShadow);
	pDC->MoveTo(rClient.right, rClient.top);
	pDC->LineTo(rClient.right, rClient.bottom);
}

CSize ToolPanelBar::ClientSize() const
{
	CSize s = PanelBar::ClientSize();
	s.cx--;
	return s;
}

CSize ToolPanelBar::GetMinWindowSize() const
{
	CSize s = PanelBar::GetMinWindowSize();
	s.cx++;
	return s;
}

void ToolPanelBar::LayoutControls()
{
	PanelBar::LayoutControls();
}


// RightPanelBar

RightPanelBar::RightPanelBar(Frame & f) : PanelBar(f) 
{
	m_Frame.Add(this);
}

CRect RightPanelBar::Bounds() const
{
	CRect r = m_Frame.GetClientRect();
	if (m_Frame.m_StatusBar.m_hWnd != 0 && m_Frame.m_StatusBar.GetStyle() & WS_VISIBLE)
		r.bottom -= StatusHeight;
	r.left = r.right - m_Frame.m_RightSplit;
	if (m_Frame.m_BottomBar.Visible())
		r.bottom -= m_Frame.m_BottomSplit;
	r.bottom -= SplitterSize;
	return r;
}

bool RightPanelBar::Visible() const
{
	return m_Frame.m_RightVisible;
}

// BottomPanelBar

BottomPanelBar::BottomPanelBar(Frame & f) : PanelBar(f) 
{
	m_Frame.Add(this);
}

CRect BottomPanelBar::Bounds() const
{
	CRect r = m_Frame.GetClientRect();
	if (m_Frame.m_StatusBar.m_hWnd != 0 && m_Frame.m_StatusBar.GetStyle() & WS_VISIBLE)
		r.bottom -= StatusHeight;
	r.top = r.bottom - m_Frame.m_BottomSplit;
	return r;
}

bool BottomPanelBar::Visible() const
{
	return m_Frame.m_BottomVisible;
}


// WidgetPanel

CSize WidgetPanel::GetMinClientSize() const
{ 
	return m_Widget.GetPreferredSize() + CSize(m_Border * 2, m_Border * 2);
}

void WidgetPanel::LayoutControls() 
{
	m_Widget.SetBounds(m_Border, m_Border + GetHeaderHeight(), ClientWidth() - m_Border, ClientHeight() - m_Border);
}


} // My
